package formatter

import (
	"bytes"
	"fmt"
	"gitee.com/go-boot/boot-interfaces/ilogger"
	"strings"
	"time"
)

type ColorType int

const (
	colorReset   ColorType = 0
	colorRed               = 31
	colorGreen             = 32
	colorYellow            = 33
	colorBlue              = 34
	colorMagenta           = 35
	colorCyan              = 36
	colorWhite             = 37
)

var (
	red     = []byte("\033[31m")
	green   = []byte("\033[32m")
	yellow  = []byte("\033[33m")
	blue    = []byte("\033[34m")
	magenta = []byte("\033[35m")
	cyan    = []byte("\033[36m")
	white   = []byte("\033[97m")
	reset   = []byte("\033[0m")
)

func colorStr(color ColorType, ctx string) []byte {
	var result []byte
	switch color {
	case colorRed:
		result = append(result, red...)
	case colorGreen:
		result = append(result, green...)
	case colorYellow:
		result = append(result, yellow...)
	case colorMagenta:
		result = append(result, magenta...)
	case colorCyan:
		result = append(result, cyan...)
	case colorWhite:
		result = append(result, white...)
	case colorBlue:
		result = append(result, blue...)
	default:
		result = append(result, blue...)
	}

	result = append(result, []byte(ctx)...)
	result = append(result, reset...)
	return result
}

type TextFormatter struct {
	ForceColors  bool //
	DisableColor bool // 是否禁用颜色
}

func DefaultTextFormatter() *TextFormatter {
	return &TextFormatter{
		ForceColors:  false,
		DisableColor: false,
	}
}

func (t *TextFormatter) Format(entry ilogger.IEntry) ([]byte, error) {
	var (
		timeData time.Time
		mapData  map[string]any
		buf      *bytes.Buffer
		getLevel = func(level ilogger.LogLevel) string {
			switch level {
			case ilogger.InfoLevel:
				return "Info"
			case ilogger.DebugLevel:
				return "Debug"
			case ilogger.WarnLevel:
				return "Warn"
			case ilogger.ErrorLevel:
				return "Error"
			case ilogger.FailLevel:
				return "Fail"
			default:
				return "Other"
			}
		}
		getColorLevel = func(level ilogger.LogLevel) []byte {

			switch level {
			case ilogger.InfoLevel:
				return colorStr(colorBlue, fmt.Sprintf("[%5s]", "INFO"))
			case ilogger.DebugLevel:
				return colorStr(colorGreen, fmt.Sprintf("[%5s]", "DEBUG"))
			case ilogger.WarnLevel:
				return colorStr(colorYellow, fmt.Sprintf("[%5s]", "WARN"))
			case ilogger.ErrorLevel:
				return colorStr(colorRed, fmt.Sprintf("[%5s]", "ERROR"))
			case ilogger.FailLevel:
				return colorStr(colorRed, fmt.Sprintf("[%5s]", "FAIL"))
			default:
				return colorStr(colorWhite, fmt.Sprintf("[%5s]", "OTHER"))
			}
		}
		//funcName  any
		fileName any
		ok       bool
	)
	mapData, buf = entry.ToMap(), &bytes.Buffer{}
	timeData = mapData[ilogger.FieldKeyTime].(time.Time)
	if t.DisableColor {
		buf.Write([]byte(fmt.Sprintf("[%s|%s|%s] ",
			mapData[ilogger.FieldKeyPrefix],
			timeData.Format(ilogger.DefaultTimeFormatWithMilli),
			getLevel(mapData[ilogger.FieldKeyLevel].(ilogger.LogLevel)))),
		)
	} else {
		buf.Write(colorStr(colorCyan, mapData[ilogger.FieldKeyPrefix].(string)))
		buf.Write([]byte("|"))
		buf.Write(colorStr(colorWhite, timeData.Format(ilogger.DefaultTimeFormat)))
		buf.WriteByte(' ')
		buf.Write(getColorLevel(mapData[ilogger.FieldKeyLevel].(ilogger.LogLevel)))
		buf.WriteRune(' ')
	}
	if fileName, ok = mapData[ilogger.FieldKeyFile]; ok {
		name := fileName.(string)
		buf.Write(colorStr(colorWhite, fmt.Sprintf("[%15s] ", name[strings.LastIndex(name, "/")+1:])))
	}
	buf.Write([]byte(fmt.Sprintf("%s ", mapData[ilogger.FieldKeyMsg])))
	buf.WriteByte('\n')
	return buf.Bytes(), nil
}
